// 线程安全的 Counter ，这里仅仅展示多线程示例，实际项目中应该用原子操作。
// 但如果 Counter 对象是被动态创建的，对象销毁时不是线程安全的。
#include <muduo/base/Mutex.h>
#include <muduo/base/Thread.h>
#include <boost/noncopyable.hpp>
#include <stdio.h>

using muduo::MutexLock;
using muduo::MutexLockGuard;

class Counter : boost::noncopyable {
public:
	Counter()
		: _value(0) 
	{}

	Counter& operator=(const Counter &rhs) {
		if (this == &rhs)
			return *this;
		MutexLockGuard myLock(_mutex); // potential dead lock
		MutexLockGuard itsLock(rhs._mutex);
		_value = rhs._value;
		return *this;
	}

	int64_t value() const {
		MutexLockGuard lock(_mutex);
		return _value;
	}

	int64_t GetAndIncrease() {
		MutexLockGuard lock(_mutex);
		int64_t ret = _value++;
		return ret;
	}

	friend void Swap(Counter &a, Counter &b);

private:
	mutable MutexLock _mutex;
	int64_t _value;
};

// 如果同时读写同一个 class 的两个对象，有潜在死锁的可能。
// 如果线程 A 执行 swap(a, b) 而线程 B 执行 swap(b, a) 便会发生死锁。
// 如果一个函数想要锁住相同类型的多个对象，为了始终保证按相同的顺序加锁，
// 可以比较 mutex 对象地址，始终先加锁地址较小的 mutex 。
void
Swap(Counter &a, Counter &b) {
	MutexLockGuard alock(a._mutex); // potential dead lock
	MutexLockGuard bLock(b._mutex);
	int64_t value = a._value;
	a._value = b._value;
	b._value = value;
}

int main() {
	Counter c;
	printf("%ld\n", c.GetAndIncrease());
}